package com.youlu.campus.service.ca;

import com.alibaba.fastjson.JSON;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.ca.UserCa;
import com.youlu.campus.service.ca.impl.CaCertificateConfigService;
import com.youlu.campus.service.ca.impl.CertificateActivityConfigService;
import com.youlu.campus.service.cache.CacheActivityService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserCaReceiveHistoryService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CacheActivityService cacheActivityService;


    @Autowired
    private CertificateActivityConfigService certificateActivityConfigService;

    @Autowired
    private CaCertificateConfigService caCertificateConfigService;

    @Autowired
    private CaTemplateService caTemplateService;

    @Autowired
    private MapperFacade mapperFacade;




    public List<UserCaReceiveActivity> list(UserPO currentUser,Set<String> userList,String queryActivityId){
        String currentPlatform = currentUser.getCurrentPlatform();
        String appId = currentUser.getAppId();
        log.info("【电子证书】appId -> {} | platform ->{} | userId->{}",appId,currentPlatform,currentUser.getId());
        List<UserCaReceiveHistory> list = null;
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").in(userList));
        if(StringUtils.isNotBlank(queryActivityId)){//第三方第二课堂使用
            query.addCriteria(Criteria.where("activityId").is(queryActivityId));
            List<UserPaperCaReceiveHistory> userPaperCaReceiveList = this.mongoTemplate.find(query, UserPaperCaReceiveHistory.class);
            if(CollectionUtils.isNotEmpty(userPaperCaReceiveList)){
                list = mapperFacade.mapAsList(userPaperCaReceiveList,UserCaReceiveHistory.class);
                log.info("【对象转换】oldZize :{}| size:{}",userPaperCaReceiveList.size(),list.size());
            }
        }else{
            list = this.mongoTemplate.find(query, UserCaReceiveHistory.class);
        }
        if(CollectionUtils.isEmpty(list)){
            return Collections.EMPTY_LIST;
        }
        //过滤QQ平台电子证书
        if(!"qq".equals(currentPlatform)||!"qq-h5".equals(currentPlatform)){
            Date now =  new Date();
            //如果是H5只查询30天
            final int dayCount = 30;
            final String h5Platform ="wechat-h5";
            final String miniPlatform ="wechat-mini";
            List<UserCaReceiveHistory> h5CaList = list.stream().filter(userCaReceiveHistory -> (h5Platform.equals(userCaReceiveHistory.getPlatform()) && userCaReceiveHistory.getCreatedTime().toInstant().plus(dayCount, ChronoUnit.DAYS).isAfter(now.toInstant()))).collect(Collectors.toList());
            List<UserCaReceiveHistory> miniCaList = list.stream().filter(userCaReceiveHistory -> miniPlatform.equals(userCaReceiveHistory.getPlatform())).collect(Collectors.toList());
            list.clear();
            if(CollectionUtils.isNotEmpty(miniCaList)){
                list.addAll(miniCaList);
            }
            if(CollectionUtils.isNotEmpty(h5CaList)){
                list.addAll(h5CaList);
            }
        }
        List<UserCaReceiveActivity> userCaReceiveActivityList = new ArrayList<>();
        Map<String, List<UserCaReceiveHistory>> caMapHistory =
                list.stream().sorted(Comparator.comparing(UserCaReceiveHistory::getCreatedTime).reversed()).collect(Collectors.toList()).stream().collect(Collectors.groupingBy(userCaReceiveHistory -> userCaReceiveHistory.getActivityId()));
        caMapHistory.forEach((activityId,item)->{
            UserCaReceiveHistory userCaReceiveHistory = item.get(0);
            UserCaReceiveActivity userCaReceiveActivity = new UserCaReceiveActivity();
            userCaReceiveActivity.setActivityId(activityId);
            ActivityInfo activityInfo = cacheActivityService.findById(activityId);
            if(Objects.nonNull(activityInfo)){
                userCaReceiveActivity.setCreatedTime(activityInfo.getCreatedTime());
            }
            userCaReceiveActivity.setActivityName(userCaReceiveHistory.getActivityName());
            userCaReceiveActivity.setCaReceiveHistoryList(item.stream().sorted(Comparator.comparing(UserCaReceiveHistory::getCreatedTime).reversed()).collect(Collectors.toList()));
            userCaReceiveActivityList.add(userCaReceiveActivity);
        });
        caMapHistory.clear();
        return userCaReceiveActivityList.stream().sorted(Comparator.comparing(UserCaReceiveActivity::getCreatedTime).reversed()).collect(Collectors.toList());
    }


    @Async
    public void saveOrUpdate(UserCaReceiveHistory userCaReceiveHistory){
        String userId = userCaReceiveHistory.getUserId();
        String caType = userCaReceiveHistory.getCaType();
        String caLevel = userCaReceiveHistory.getCaLevel();
        String activityId = userCaReceiveHistory.getActivityId();
        if(StringUtils.isBlank(userId)||StringUtils.isBlank(caType)||StringUtils.isBlank(caLevel)||StringUtils.isBlank(activityId)){
            log.error("【电子证书】插入或更新缺少必传参数");
            return;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("caType").is(caType));
        query.addCriteria(Criteria.where("caLevel").is(caLevel));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        Update update = new Update();
        Date now =new Date();
        boolean exists = this.mongoTemplate.exists(query, UserCaReceiveHistory.class);
        if(!exists){
            update.set("createdTime",now);
        }
        update.set("updatedTime",now);
        if(StringUtils.isNotBlank(userCaReceiveHistory.getCaTemplateId())){
            update.set("caTemplateId",userCaReceiveHistory.getCaTemplateId());
        }
        if(StringUtils.isNotBlank(userCaReceiveHistory.getCaTemplateImgUrl())){
            update.set("caTemplateImgUrl",userCaReceiveHistory.getCaTemplateImgUrl());
        }
        if(Objects.nonNull(userCaReceiveHistory.getReceiveTime())){
            update.set("receiveTime",userCaReceiveHistory.getReceiveTime());
        }
        if(StringUtils.isNotBlank(userCaReceiveHistory.getActivityName())){
            update.set("activityName",userCaReceiveHistory.getActivityName());
        }
        if(StringUtils.isNotBlank(userCaReceiveHistory.getAppId())){
            update.set("appId",userCaReceiveHistory.getAppId());
        }
        if(StringUtils.isNotBlank(userCaReceiveHistory.getPlatform())){
            update.set("platform",userCaReceiveHistory.getPlatform());
        }
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.upsert(Boolean.TRUE);
        findAndModifyOptions.returnNew(Boolean.TRUE);
        this.mongoTemplate.findAndModify(query,update,findAndModifyOptions,UserCaReceiveHistory.class);
    }

    @Getter
    @Setter
    public class UserCaReceiveActivity{
        private String activityId;
        private String activityName;
        private Date createdTime;
        private List<UserCaReceiveHistory> caReceiveHistoryList;
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

}
